
#include <BVBoxLayout>
#include <BHBoxLayout>
#include <BGridLayout>
#include <BStyle>
#include <BPainter>
#include <BImage>
#include <BReadWrite>
#include <BTableItem>
#include <BColorDialog>
#include <BButtonGroup>
#include <BSphereHandler>
#include <BMessageBox>
#include <BEvent>
#include <BScene>
#include <BLight>

#include "MateHandler.h"
#include "TexturePanel.h"
#include "MaterialDialog.h"

MaterialDialog::MaterialDialog(BWidget* parent) : BDialog(parent)
{
	this->setTitle("Material");
	_mateView = initViewer();

	BHBoxLayout* buttonLayout = new BHBoxLayout();
	{
		_createButton = new BButton("create");
		_deleteButton = new BButton("delete");

		BButton* sphereButton = new BButton("sphere");
		sphereButton->setForm(Form_IconAlone);
		BButton* cubeButton = new BButton("cube");
		cubeButton->setForm(Form_IconAlone);
		BButton* cylinderButton = new BButton("cylinder");
		cylinderButton->setForm(Form_IconAlone);

		buttonLayout->addWidget(_createButton);
		buttonLayout->addWidget(_deleteButton);
		buttonLayout->addWidget(sphereButton);
		buttonLayout->addWidget(cubeButton);
		buttonLayout->addWidget(cylinderButton);

		_shapeButtonGroup = new BButtonGroup();
		_shapeButtonGroup->setAsset((BByte)128);
		_shapeButtonGroup->addButton(sphereButton);
		_shapeButtonGroup->addButton(cubeButton);
		_shapeButtonGroup->addButton(cylinderButton);

		connect(_shapeButtonGroup, Signal_Checked, &MaterialDialog::slotShapeButtonChecked);
	}
	BGridLayout* gridLayout = new BGridLayout();
	{
		BLabel* nameLabel = new BLabel("name");
		_nameEdit = new BLineEdit();

		BLabel* ambientLabel = new BLabel("ambient");
		_ambientButton = new BButton();
		_ambientButton->setAlign(Align_Left);
		_ambientButton->setGraph(Graph_Square_Fill);

		BLabel* diffuseLabel = new BLabel("diffuse");
		_diffuseButton = new BButton();
		_diffuseButton->setAlign(Align_Left);
		_diffuseButton->setGraph(Graph_Square_Fill);

		BLabel* specularLabel = new BLabel("specular");
		_specularButton = new BButton();
		_specularButton->setAlign(Align_Left);
		_specularButton->setGraph(Graph_Square_Fill);

		BLabel* shininessLabel = new BLabel("shininess");
		_shininessSlider = new BSlider(0, 128);

		gridLayout->setWidget(0, 0, nameLabel);
		gridLayout->setWidget(0, 1, _nameEdit);
		gridLayout->setWidget(1, 0, ambientLabel);
		gridLayout->setWidget(1, 1, _ambientButton);
		gridLayout->setWidget(2, 0, diffuseLabel);
		gridLayout->setWidget(2, 1, _diffuseButton);
		gridLayout->setWidget(3, 0, specularLabel);
		gridLayout->setWidget(3, 1, _specularButton);
		gridLayout->setWidget(4, 0, shininessLabel);
		gridLayout->setWidget(4, 1, _shininessSlider);
		gridLayout->setColumnStretch(0, 0);
	}

	_addTextureButton = new BButton("Add Texture");

	_scrollWidget = new BScrollWidget();
	_scrollWidget->setTitle("Texture");
	_scrollWidget->setAreaPolicy(Policy_Preferred | Policy_Expanding, Policy_Preferred);
	_scrollWidget->addWidget(_addTextureButton);

	BVBoxLayout* vlayout = new BVBoxLayout(this);
	vlayout->addWidget(_mateView);
	vlayout->addLayout(buttonLayout);
	vlayout->addLayout(gridLayout);
	vlayout->addWidget(_scrollWidget, 1000);

	connect(this, Signal_AssetChanged, &MaterialDialog::slotAssetChanged);

	connect(_mateView, Signal_Actived, &MaterialDialog::slotMateViewActived);
	connect(_shapeButtonGroup, Signal_Checked, &MaterialDialog::slotShapeButtonChecked);
	connect(_createButton, Signal_Clicked, &MaterialDialog::slotCreateButtonClicked);
	connect(_deleteButton, Signal_Clicked, &MaterialDialog::slotDeleteButtonClicked);
	connect(_nameEdit, Signal_EditFinished, &MaterialDialog::slotNameEditFinished);
	connect(_ambientButton, Signal_Clicked, &MaterialDialog::slotAmbientEdited);
	connect(_diffuseButton, Signal_Clicked, &MaterialDialog::slotDiffuseEdited);
	connect(_specularButton, Signal_Clicked, &MaterialDialog::slotSpecularEdited);
	connect(_shininessSlider, Signal_Sliding, &MaterialDialog::slotShininessEdited);
	connect(_addTextureButton, Signal_Clicked, &MaterialDialog::slotAddTextureButtonClicked);

	_nameEdit->setEnabled(false);
	_ambientButton->setEnabled(false);
	_diffuseButton->setEnabled(false);
	_specularButton->setEnabled(false);
	_shininessSlider->setEnabled(false);

}
MaterialDialog::~MaterialDialog()
{

}

void MaterialDialog::setMaterial(BMaterial* material)
{
	if (_material != material)
	{
		_material = material;
		if (material)
		{
			_nameEdit->setText(material->name());
			_ambientButton->setColor(material->ambient());
			_diffuseButton->setColor(material->diffuse());
			_specularButton->setColor(material->specular());
			_shininessSlider->setValue(material->shininess());
		}
		else
		{
			_nameEdit->setText(BString());
			_ambientButton->setColor(BColor());
			_diffuseButton->setColor(BColor());
			_specularButton->setColor(BColor());
			_shininessSlider->setValue(0);
		}
		_nameEdit->setEnabled(material);
		_ambientButton->setEnabled(material);
		_diffuseButton->setEnabled(material);
		_specularButton->setEnabled(material);
		_shininessSlider->setEnabled(material);
		if (_shape)
		{
			_shape->setMaterial(material);
		}
		if (BShape* shape = _mateView->asset())
		{
			shape->setMaterial(material);
		}
	}
}

BViewer* MaterialDialog::initViewer()
{
	BScene* scene = new BScene();
	{
		BGeoSphere* sphere = new BGeoSphere(1, 3);
		sphere->setName("sphere");
		scene->insert(sphere);

		BCube* cube = new BCube();
		cube->setName("cube");
		cube->setVisible(false);
		scene->insert(cube);

		BCylinder* cylinder = new BCylinder();
		cylinder->setName("cylinder");
		cylinder->setVisible(false);
		scene->insert(cylinder);

		BLight* light = new BLight();
		light->setPosition(30, 30, 30);
		light->setAmbient(255, 255, 255);
		light->setDiffuse(255, 255, 255);
		light->setSpecular(255, 255, 255);
		scene->insert(light);
	}

	BCamera* camera = new BCamera();
	camera->setColor(20, 30, 40);
	camera->setPosition(0, -2, 2);
	camera->setCenter(0, 0, 0);

	BHandler* handler = new MateHandler();

	BViewer* viewer = new BViewer();
	viewer->setFixedSize(200, 200);
	viewer->setScene(scene);
	viewer->setCamera(camera);
	viewer->setHandler(handler);
	viewer->setAsset(scene->shape("sphere"));

	return viewer;
}

void MaterialDialog::slotAssetChanged(BObject* object, const BValue& value)
{
	BShape* shape = value;
	if (_shape != shape)
	{
		if (_shape)
		{
			disconnect(_shape);
			disconnect(_shape->material());
			for (int i = 0; i < _shape->textureCount(); i++)
			{
				BTexture* texture = _shape->texture(i);
				disconnect(texture);
			}
			if(BShape* shape = _mateView->asset())
			{
				shape->setMaterial(0);
				shape->setTexture(0);
			}
			_scrollWidget->clearWidgets();
		}
		_shape = shape;
		if (_shape)
		{
			setMaterial(_shape->material());
			for (int i = 0; i < _shape->textureCount(); i++)
			{
				BTexture* texture = _shape->texture(i);
				if(BShape* shape = _mateView->asset())
					shape->setTexture(texture, i);
				TexturePanel* texturePanel = new TexturePanel();
				texturePanel->setAsset(texture);
				_scrollWidget->insertWidget(_scrollWidget->index(_addTextureButton), texturePanel);
				connect(texturePanel, Signal_Changed, &MaterialDialog::slotTextureChanged);
			}
			_scrollWidget->addWidget(_addTextureButton);
		}
	}
}

void MaterialDialog::slotMateViewActived(BObject* object, const BValue& value)
{
	bool actived = value;
	if (actived)
	{
		_shapeButtonGroup->setAsset(BByte(255));
	}
	else
	{
		_shapeButtonGroup->setAsset(BByte(128));
	}

}
void MaterialDialog::slotCreateButtonClicked(BObject* object, const BValue& value)
{
	BMaterial* material = new BMaterial();
	setMaterial(material);
}
void MaterialDialog::slotDeleteButtonClicked(BObject* object, const BValue& value)
{
	setMaterial(0);
}
void MaterialDialog::slotShapeButtonChecked(BObject* object, const BValue& value)
{
	if (BButton* button = value)
	{
		const BString& text = button->text();
		BShape* shape = _mateView->asset();
		shape->setVisible(false);
		shape = _mateView->scene()->shape(text);
		shape->setVisible(true);
		_mateView->setAsset(shape);
		shape->setMaterial(_material);
		for (int i = 0; i < _shape->textureCount(); i++)
		{
			BTexture* texture = _shape->texture();
			shape->setTexture(texture, i);
		}
	}
}

void MaterialDialog::slotNameEditFinished()
{
	const BString& name = _nameEdit->text();
	if (_material)
	{
		_material->setName(name);
	}
}
void MaterialDialog::slotAmbientEdited(BObject* object, const BValue& value)
{
	BColor color = BColorDialog::ChooseColor("Color", _material->ambient());
	if (_material->ambient() != color)
	{
		_material->setAmbient(color);
		_ambientButton->setColor(color);
	}
}
void MaterialDialog::slotDiffuseEdited(BObject* object, const BValue& value)
{
	BColor color = BColorDialog::ChooseColor("Color", _material->diffuse());
	if (_material->diffuse() != color)
	{
		_material->setDiffuse(color);
		_diffuseButton->setColor(color);
	}
}
void MaterialDialog::slotSpecularEdited(BObject* object, const BValue& value)
{
	BColor color = BColorDialog::ChooseColor("Color", _material->specular());
	if (_material->specular() != color)
	{
		_material->setSpecular(color);
		_specularButton->setColor(color);
	}
}
void MaterialDialog::slotShininessEdited()
{
	int shininess = _shininessSlider->value();
	_material->setShininess(shininess);
}

void MaterialDialog::slotAddTextureButtonClicked()
{
	int unit = _shape->textureCount();
	BImage* image = new BImage();
	_shape->setTexture(image, unit);
	if (BShape* shape = _mateView->asset())
	{
		shape->setTexture(image, unit);
	}
	TexturePanel* texturePanel = new TexturePanel();
	texturePanel->setAsset(image);
	_scrollWidget->insertWidget(_scrollWidget->index(_addTextureButton), texturePanel);
	connect(texturePanel, Signal_Changed, &MaterialDialog::slotTextureChanged);
}
void MaterialDialog::slotTextureChanged(BObject* object)
{
	TexturePanel* texturePanel = dynamic_cast<TexturePanel*>(object);
	for(int i = 0; i < _scrollWidget->widgetCount(); i++)
	{
		if(_scrollWidget->widget(i) == texturePanel)
		{
			_shape->setTexture(texturePanel->asset(), i);
		}
	}
}

void MaterialDialog::showEvent(const BEvent& event)
{
	BDialog::showEvent(event);
}

void MaterialDialog::updateEvent(const BEvent& event)
{
	BByte transparency = _shapeButtonGroup->asset();
	for (int i = 0; i < _shapeButtonGroup->buttonCount(); i++)
	{
		BButton* button = _shapeButtonGroup->button(i);
		if (button->transparency() != transparency)
		{
			int diff = transparency - button->transparency();
			BByte change = abs(diff) < 4 ? diff : diff / 4;
			this->setTransparency(button->transparency() + change);
		}
	}
}

void MaterialDialog::styleEvent(const BEvent& event)
{
	if (const BStyle* style = this->realStyle())
	{
		_createButton->setIcon(style->icon("create"));
		_deleteButton->setIcon(style->icon("delete"));
	}
	BDialog::styleEvent(event);
}
void MaterialDialog::paintEvent(const BEvent& event)
{
	BDialog::paintEvent(event);
}

